package cn.com.interceptor;

import cn.com.Enum.SessionAttr;
import cn.com.Enum.UserAuth;
import cn.com.Enum.UserClientId;
import cn.com.annotation.Auth;
import cn.com.constant.Code;
import cn.com.db.Jwt.Data;
import cn.com.db.Jwt.JWT;
import cn.com.db.Jwt.Payload;
import cn.com.db.model.Admin;
import cn.com.db.model.Seller;
import cn.com.db.model.User;
import cn.com.db.service.AdminService;
import cn.com.db.service.SellerService;
import cn.com.db.service.UserService;
import cn.com.util.DataResult;
import cn.com.util.SessionUtil;
import cn.com.util.TokenUtil;
import cn.com.util.util;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.annotations.Case;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    UserService userService;
    @Autowired
    AdminService adminService;
    @Autowired
    SellerService sellerService;

    private String tokenHead="Authorization";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        DataResult dataResult=new DataResult();
        if (!(handler instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)handler;
        Method method=handlerMethod.getMethod();
        Class controllerClazz=method.getDeclaringClass();
        Auth auth=null;
        if (method.isAnnotationPresent(Auth.class)){
            auth=method.getAnnotation(Auth.class);
        }else if(controllerClazz.isAnnotationPresent(Auth.class)){
            auth=(Auth) controllerClazz.getAnnotation(Auth.class);
        }
        if (auth==null){
            dataResult.setCode(Code.FORBIDDEN);
            dataResult.setMessage("请求的api权限未知");
            util.comeBack(response, JSON.toJSONString(dataResult));
            return false;
        }
        UserAuth[] auths=auth.value();
        List<UserAuth> authList= Arrays.asList(auths);
        if (authList.contains(UserAuth.ALL)){
            return true;
        }else {
            String token=request.getHeader(tokenHead);
            if (StringUtils.isBlank(token)){
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("令牌未找到:"+Code.TOKEN_NOT_FOUNE);
                util.comeBack(response, JSON.toJSONString(dataResult));
                return false;
            }
            JWT jwt= null;
            try {
                jwt = TokenUtil.parseToken(token);
            }catch (UnsupportedEncodingException e) {
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("令牌错误,解析异常:"+Code.ERROR_TOKEN);
                util.comeBack(response,JSON.toJSONString(dataResult));
                return false;
            }catch (TokenExpiredException e){
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("令牌已过期,需要重新登录:"+Code.TOKEN_EXP);
                util.comeBack(response,JSON.toJSONString(dataResult));
                return false;
            }catch (InvalidClaimException e){
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("令牌错误,解析失败:"+Code.TOKEN_INVALID_CLAIM);
                util.comeBack(response,JSON.toJSONString(dataResult));
                return false;
            }catch (Exception e){
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("令牌错误,解析失败:"+Code.ERROR_TOKEN);
                util.comeBack(response,JSON.toJSONString(dataResult));
                return false;
            }
            Payload payload=jwt.getPayload();
            Data data=payload.getData();
            if(data==null){
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("令牌错误:"+Code.ERROR_TOKEN);
                util.comeBack(response,JSON.toJSONString(dataResult));
                return false;
            }
            UserClientId clientId=data.getClientId();
            if (clientId==null){
                dataResult.setCode(Code.FORBIDDEN);
                dataResult.setMessage("无法识别令牌权限:");
                util.comeBack(response,JSON.toJSONString(dataResult));
                return false;
            }
            switch (clientId){
                case USER:
                    User user=userService.getUserAuthingId(data.getId());
                    if (user==null){
                        dataResult.setCode(Code.FORBIDDEN);
                        dataResult.setMessage("令牌错误:"+Code.USERID_NOT_FOUND);
                        util.comeBack(response, JSON.toJSONString(dataResult));
                        return false;
                    }
                    if (!authList.contains(UserAuth.USER)){
                        dataResult.setCode(Code.FORBIDDEN);
                        dataResult.setMessage("权限不足");
                        util.comeBack(response, JSON.toJSONString(dataResult));
                        return false;
                    }
                    SessionUtil.addAttr(request, SessionAttr.USERAUTHINGID,data.getId());
                    break;
                case ADMIN:
                    Admin admin=adminService.getAdminByAuthingId(data.getId());
                    if (admin == null) {
                        dataResult.setCode(Code.FORBIDDEN);
                        dataResult.setMessage("令牌错误:"+Code.ADMINID_NOT_FOUND);
                        util.comeBack(response, JSON.toJSONString(dataResult));
                        return false;
                    }
                    if (!authList.contains(UserAuth.ADMIN)){
                        dataResult.setCode(Code.FORBIDDEN);
                        dataResult.setMessage("权限不足");
                        util.comeBack(response, JSON.toJSONString(dataResult));
                        return false;
                    }
                    SessionUtil.addAttr(request, SessionAttr.ADMINAUTHINGID,data.getId());
                    break;
                case SELLER:
                    Seller seller=sellerService.getSellerByAuthingId(data.getId());
                    if (seller == null) {
                        dataResult.setCode(Code.FORBIDDEN);
                        dataResult.setMessage("令牌错误:"+Code.SELLER_NOT_FOUND);
                        util.comeBack(response, JSON.toJSONString(dataResult));
                        return false;
                    }
                    if (!authList.contains(UserAuth.SELLER)){
                        dataResult.setCode(Code.FORBIDDEN);
                        dataResult.setMessage("权限不足");
                        util.comeBack(response, JSON.toJSONString(dataResult));
                        return false;
                    }
                    SessionUtil.addAttr(request, SessionAttr.SELLERAUTHINGID,data.getId());
                    break;
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

}
